<?php declare(strict_types=1);


namespace App\Service;

use App\Dao\FileDao;
use App\Dao\FileUploadTempDao;
use App\Model\FileUploadTemp;
use Swoole\Exception;
use Hyperf\Database\Exception\QueryException;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpMessage\Exception\UnsupportedMediaTypeHttpException;


/**
 * 文件操作服务，涉及的数据表有两个 file、file_upload_temp
 * Class FileService
 * @package App\Service
 */
class FileService
{
    /** @var string 文件hash加密的附加字符 */
    public const TEMP_HASH = '$:1$';

    public const ROOT = BASE_PATH.'/';

    public const UPLOAD = 'upload';

    /**
     * @Inject()
     * @var FileUploadTempDao
     */
    private $fut;

    /**
     * @Inject()
     * @var FileDao
     */
    private $fileDao;

    /**
     * @return string 根据日期获取文件夹目录
     */
    public function getFileDirPath(): string
    {
        // 根据日期生成文件夹
        $date = date('Y-m-d');
        $path = self::ROOT . self::UPLOAD .'/'.$date;
        if (!mkdir($path) && !is_dir($path)) {
            throw new UnsupportedMediaTypeHttpException('文件创建失败');
        }
        return  'upload/' . $date . '/';
    }

    /**
     * @param $baseName
     * @return string
     */
    public function genFileName($baseName): string
    {
        return md5($baseName);
    }

    /**
     * 生成文件路径和文件名
     * @param $baseName
     * @param $extension
     * @return string
     */
    public function genFilePath($baseName,$extension): string
    {
        return $this->getFileDirPath()
            . $this->genFileName($baseName).
            '.'.$extension;
    }




    /**
     * 文件上传写入临时表
     * @param $record [
     * 'created_by' =>
     * 'created_id'  =>
     * 'file_name'  =>
     * 'path'  =>
     * 'suffix'  =>
     * 'size'  =>
     * ]
     * @return FileUploadTemp
     * @throws Exception
     */
    public function recordTempFile($record): FileUploadTemp
    {
        $record['hash'] = $this->genHashVal();
        if($model = $this->fut->insert($record)){
            return $model;
        }
    }

    /**
     * 获取临时文件
     * @param $hash
     * @return \Hyperf\Database\Model\Builder|\Hyperf\Database\Model\Model|object|null|FileUploadTemp
     */
    public function getTempFile($hash)
    {
        return $this->fut->getModel($hash);
    }

    /**
     * 将文件写入文件表，并且删除临时表状态改为已使用
     * @param $user
     * @param $hash
     * @param $moduleId
     * @param $eventId
     * @param int $index
     * @return array
     * @throws Exception
     */
    public function writeFile(&$user, $hash, $moduleId, $eventId, $index = 0): array
    {
        $fileInfo = $this->fut->getModel($hash);
        if(!$fileInfo){
            throw new Exception('获取不到资源文件，请确认文件已上传');
        }
        $fileData = [
            'module_id' => $moduleId,
            'event_id' => $eventId,
            'index' => $index,
            'class' => $user['class'],
            'path' => $fileInfo->path,
            'file_name' => $fileInfo->file_name,
            'suffix' => $fileInfo->suffix,
            'size' => $fileInfo->size,
            'created_by' => $user['stu_num'],
            'created_id' => $user['id']
        ];
        // 开启事务
        Db::beginTransaction();
        try{
            // 正式文件插入
            $this->fileDao->insert($fileData);
            // 临时文件状态修改
            $fileInfo->where('hash', $hash);
            $this->fut->inUse($fileInfo);
            Db::commit();
            return $fileData;
        } catch (QueryException $exception) {
            Db::rollBack();
            throw new Exception($exception->getMessage());
        }
    }

    /**
     * 生成临时文件hash
     * @throws Exception
     */
    private function genHashVal(): string
    {
        $microTime = microtime().random_bytes(5);
        return md5(base64_encode($microTime.self::TEMP_HASH));
    }




}